package com.example.fury.loglistwidget;

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

/**
 * Our data observer just notifies an update for all Log widgets when it detects
 * a change.
 */
class LogDataProviderObserver extends ContentObserver {

	private static final String TAG = LogDataProviderObserver.class
			.getSimpleName();

	private AppWidgetManager mAppWidgetManager;
	private ComponentName mComponentName;

	LogDataProviderObserver(AppWidgetManager mgr, ComponentName cn, Handler h) {
		super(h);
		mAppWidgetManager = mgr;
		mComponentName = cn;
	}

	@Override
	public void onChange(boolean selfChange) {
		// The data has changed, so notify the widget that the collection view
		// needs to be updated.
		// In response, the factory's onDataSetChanged() will be called which
		// will requery the
		// cursor for the new data.
		Log.d(TAG, "onChange|notifyAppWidgetViewDataChanged");
		mAppWidgetManager.notifyAppWidgetViewDataChanged(
				mAppWidgetManager.getAppWidgetIds(mComponentName),
				R.id.log_list);
	}
}

/**
 * The Log widget's AppWidgetProvider.
 */
public class LogWidgetProvider extends AppWidgetProvider {

	private static final String TAG = LogWidgetProvider.class.getSimpleName();

	public static String CLICK_ACTION = "com.example.fury.loglistwidget.CLICK";
	public static String REFRESH_ACTION = "com.example.fury.loglistwidget.REFRESH";
	public static String EXTRA_LOG_ID = "com.example.fury.loglistwidget.log";

	// private static final int REFRESH_RATE = 150000;
	private Prefs mPrefs = null;

	private static HandlerThread sWorkerThread;
	private static Handler sWorkerQueue;

	// private static LogDataProviderObserver sDataObserver;

	public LogWidgetProvider() {

		Log.d(TAG, "Start the worker thread");
		// Start the worker thread
		if (sWorkerThread == null) {
			sWorkerThread = new HandlerThread("LogWidgetProvider-worker");
			sWorkerThread.start();
			sWorkerQueue = new Handler(sWorkerThread.getLooper());
		}
		Log.d(TAG, "End the worker thread");
	}

	@Override
	public void onEnabled(Context context) {
		// Register for external updates to the data to trigger an update of the
		// widget. When using
		// content providers, the data is often updated via a background
		// service, or in response to
		// user interaction in the main app. To ensure that the widget always
		// reflects the current
		// state of the data, we must listen for changes and update ourselves
		// accordingly.

		Log.d(TAG, "onEnabled");
		// final ContentResolver r = context.getContentResolver();
		// if (sDataObserver == null) {
		// Log.d(TAG, "onEnabled|register Data Observer");
		// final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
		// final ComponentName cn = new ComponentName(context,
		// LogWidgetProvider.class);
		// sDataObserver = new LogDataProviderObserver(mgr, cn, sWorkerQueue);
		// r.registerContentObserver(LogDataProvider.CONTENT_URI, true,
		// sDataObserver);
		// }

		mPrefs = new Prefs(context);
		// Bind the click intent for the refresh button on the widget
		final Intent refreshIntent = new Intent(context,
				LogWidgetProvider.class);

		final AlarmManager mgr = (AlarmManager) context
				.getSystemService(Context.ALARM_SERVICE);
		// final Intent alarmIntent = new Intent(context,
		// LogWidgetProvider.class);
		refreshIntent.setAction(LogWidgetProvider.REFRESH_ACTION);
		final PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(
				context, 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		mgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
				SystemClock.elapsedRealtime(), mPrefs.getRefreshFrequency()
						.getValue() // REFRESH_RATE
				, alarmPendingIntent);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.appwidget.AppWidgetProvider#onDisabled(android.content.Context)
	 */
	@Override
	public void onDisabled(Context context) {

		Log.d(TAG, "clearAlarm");
		AlarmManager alarmManager = (AlarmManager) context
				.getSystemService(Context.ALARM_SERVICE);
		final Intent refreshIntent = new Intent(context,
				LogWidgetProvider.class);
		refreshIntent.setAction(LogWidgetProvider.REFRESH_ACTION);
		// Bind the click intent for the refresh button on the widget

		// cancel the pending intent!
		// Intent alarmIntent = new Intent(LogWidgetProvider.REFRESH_ACTION);
		PendingIntent pIntent = PendingIntent.getBroadcast(context, 0,
				refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
		alarmManager.cancel(pIntent);

		super.onDisabled(context);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.appwidget.AppWidgetProvider#onDeleted(android.content.Context,
	 * int[])
	 */
	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		// TODO Auto-generated method stub
		Log.d(TAG, "onDeleted");
		super.onDeleted(context, appWidgetIds);
	}

	@Override
	public void onReceive(Context ctx, Intent intent) {

		Log.d(TAG, "onReceive");

		final String action = intent.getAction();
		if (action.equals(REFRESH_ACTION)) {
			// BroadcastReceivers have a limited amount of time to do work, so
			// for this sample, we
			// are triggering an update of the data on another thread. In
			// practice, this update
			// can be triggered from a background service, or perhaps as a
			// result of user actions
			// inside the main application.
			final Context context = ctx;
			Log.d(TAG, "onReceive|posting Runnable");
			sWorkerQueue.removeMessages(0);
			sWorkerQueue.post(new Runnable() {
				@Override
				public void run() {
					// final ContentResolver r = context.getContentResolver();
					// final Cursor c = r.query(LogDataProvider.CONTENT_URI,
					// null,
					// null, null, null);

					Log.d(TAG, "onReceive|run");
					final AppWidgetManager mgr = AppWidgetManager
							.getInstance(context);
					final ComponentName cn = new ComponentName(context,
							LogWidgetProvider.class);
					Log.d(TAG, "onReceive|notifyAppWidgetViewDataChanged");
					mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn),
							R.id.log_list);
				}
			});
		} else if (action.equals(CLICK_ACTION)) {
			// Show a toast
			Log.d(TAG, "onReceive|click");
			// final int appWidgetId = intent.getIntExtra(
			// AppWidgetManager.EXTRA_APPWIDGET_ID,
			// AppWidgetManager.INVALID_APPWIDGET_ID);
			final String log = intent.getStringExtra(EXTRA_LOG_ID);
			final String formatStr = ctx.getResources().getString(
					R.string.toast_format_string);
			Toast.makeText(ctx, String.format(formatStr, log),
					Toast.LENGTH_SHORT).show();
		}

		super.onReceive(ctx, intent);
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {

		Log.d(TAG, "onUpdate");
		// Update each of the widgets with the remote adapter
		for (int i = 0; i < appWidgetIds.length; i++) {
			// Specify the service to provide data for the collection widget.
			// Note that we need to
			// embed the appWidgetId via the data otherwise it will be ignored.
			final Intent intent = new Intent(context, LogWidgetService.class);
			intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
					appWidgetIds[i]);
			intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
			final RemoteViews rv = new RemoteViews(context.getPackageName(),
					R.layout.widget_layout);
			rv.setRemoteAdapter(appWidgetIds[i], R.id.log_list, intent);

			// Set the empty view to be displayed if the collection is empty. It
			// must be a sibling
			// view of the collection view.
			rv.setEmptyView(R.id.log_list, R.id.empty_view);

			// Bind a click listener template for the contents of the Log list.
			// Note that we
			// need to update the intent's data if we set an extra, since the
			// extras will be
			// ignored otherwise.
			final Intent onClickIntent = new Intent(context,
					LogWidgetProvider.class);
			onClickIntent.setAction(LogWidgetProvider.CLICK_ACTION);
			onClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
					appWidgetIds[i]);
			onClickIntent.setData(Uri.parse(onClickIntent
					.toUri(Intent.URI_INTENT_SCHEME)));
			final PendingIntent onClickPendingIntent = PendingIntent
					.getBroadcast(context, 0, onClickIntent,
							PendingIntent.FLAG_UPDATE_CURRENT);
			rv.setPendingIntentTemplate(R.id.log_list, onClickPendingIntent);

			Log.d(TAG, "onUpdate" + i);
			appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
		}
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}
}